package com.teaphy.type;

import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class TypeDemo<T, K extends Number> {
	
	public List<String> list;
	public Map.Entry<String, String> entry;
	public List<String>[] listArrays;
	public T[] ts;
	public List<? extends Number> listExtends;
	public List<? super Number> listSuper;
	public Map<? extends String, ? super String> map;
	
	public static void main(String[] args) {
		
		// 1. ParameterizedType
		System.out.println("ParameterizedType --> Start");
		try {
			Field listField = TypeDemo.class.getField("list");
			Type listGenericType = listField.getGenericType();
			System.out.println("List<String>.getGenericType()：" + listGenericType);
			// 判断getGenericType()是否为ParameterizedType
			// 当需要描述的参数化类型时，比如List<T>,Map<String,Integer>等，Java会选择ParameterizedType接
			// 口做为Type的实现。
			if (listGenericType instanceof ParameterizedType) {
				
				ParameterizedType parameterizedType = (ParameterizedType) listGenericType;
				// 1. getActualTypeArguments()：返回表示此类型实际类型参数的 Type 对象的数组。
				// 参数化的实参类型可能不是一个，比如Map<String, Integer>，所以返回一个Type数组
				// 值得注意的是：
				// 无论<>中有几层嵌套(List<Map<String,Integer>)，getActualTypeArguments()方法永远都是
				// 脱去最外层的<>(也就是List<>)，将口号内的内容（Map<String,Integer>）返回；
				Type[] listTypes = parameterizedType.getActualTypeArguments();
				// 将Type强转为Class
				Class listGenClass = (Class) listTypes[0];
				System.out.println("listTypes: " + Arrays.toString(listTypes));
				System.out.println("listGenClass: " + listGenClass);
				
				// 2. getRawType()：获取声明泛型的类或者接口，也就是泛型中<>前面的那个值
				Type rawType = parameterizedType.getRawType();
				System.out.println("getRawType(): " + rawType);
				
				// 3. getRawType()： 返回表示此类型所属类型的Type对象。例如，如果此类型为O<T>.I<S>，则返回O<T>。
				// 如果此类型是top_level类型，则返回null。可以理解为内部类的所属类。
				Type ownerType = parameterizedType.getOwnerType();
				System.out.println("getOwnerType(): " + ownerType);
			}
			
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		
		try {
			Field entryField = TypeDemo.class.getField("entry");
			Type entryGenericType = entryField.getGenericType();
			
			// 判断getGenericType()是否为ParameterizedType
			// 当需要描述的参数化类型时，比如List<T>,Map<String,Integer>等，Java会选择ParameterizedType接
			// 口做为Type的实现。
			if (entryGenericType instanceof ParameterizedType) {
				
				ParameterizedType parameterizedType = (ParameterizedType) entryGenericType;
				// 3. getRawType()： 返回表示此类型所属类型的Type对象。例如，如果此类型为O<T>.I<S>，则返回O<T>。
				// 如果此类型是top_level类型，则返回null。可以认为，如果这个类型是内部类，将返回其所属类。
				Type ownerType = parameterizedType.getOwnerType();
				System.out.println("getOwnerType(): " + ownerType);
			}
			
			
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		
		System.out.println("End --> ParameterizedType");
		
		// 2. GenericArrayType
		// GenericArrayType表示一种数组类型，其组件类型是参数化类型或类型变量，如T[], List<String>[]。
		System.out.println("GenericArrayType --> Start");
		
		try {
			Field listArraysField = TypeDemo.class.getField("listArrays");
			Type typeListArray = listArraysField.getGenericType();
			if (typeListArray instanceof GenericArrayType) {
				GenericArrayType genericArrayType = (GenericArrayType) typeListArray;
				// 返回泛型数组中元素的Type类型，
				// 即List<String>[] 中的 List<String>（ParameterizedTypeImpl）、T[] 中的T（TypeVariableImpl）
				// 此时，type为sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
				Type type = genericArrayType.getGenericComponentType();
				System.out.println("GenericArrayType.getGenericComponentType()：" + type);
				ParameterizedType ptListArray = (ParameterizedType)type;
				// 获取参数化类型列表
				Type[] actualTypeArguments = ptListArray.getActualTypeArguments();
				// 打印：actualTypeArguments: [class java.lang.String]
				System.out.println("actualTypeArguments: " + Arrays.toString(actualTypeArguments));
			}
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		
		try {
			Field ts = TypeDemo.class.getField("ts");
			Type genericType = ts.getGenericType();
			
			if (genericType instanceof GenericArrayType) {
				GenericArrayType genericArrayType = (GenericArrayType) genericType;
				// 此时，type为sun.reflect.generics.reflectiveObjects.TypeVariableImpl
				Type genericComponentType = genericArrayType.getGenericComponentType();
				TypeVariable typeVariable = (TypeVariable) genericComponentType;
				System.out.println(typeVariable.getName());
				System.out.println(Arrays.toString(typeVariable.getBounds()));
				// getGenericDeclaration()：返回GenericDeclaration对象，就是声明该类型变量实体(即获得类、方法或构造器名)
				System.out.println(typeVariable.getGenericDeclaration());
			}
			
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		
		System.out.println("End --> GenericArrayType");
		
		// 3. TypeVariable
		System.out.println("TypeVariable<D extends GenericDeclaration> --> Start");
		
		Class clz = TypeDemo.class;
		TypeVariable[] typeParameters = clz.getTypeParameters();
		System.out.println("Class.getTypeParameters()：" + Arrays.toString(typeParameters));
		System.out.println("------------------------");
		for (TypeVariable variable : typeParameters) {
			// 获取声明该类型变量实体(即获得类、方法或构造器名)
			System.out.println("声明该类型变量实体：" + variable.getGenericDeclaration());
			// 获取泛型的上限，若未明确声明上边界则默认为Object
			System.out.println("声明的泛型名称：" + Arrays.toString(variable.getBounds()));
			// 获取泛型名称，即K、V、E之类名称
			System.out.println("声明的泛型名称：" + variable.getName());
			System.out.println("------------------------");
		}
		System.out.println("End --> TypeVariable<D extends GenericDeclaration>");
		
		// 4. WildcardType
		System.out.println("WildcardType --> Start");
		
		try {
			System.out.println("-------- List<? extends Number> ----");
			
			Field listExtends = TypeDemo.class.getField("listExtends");
			printWildcardType(listExtends);
			
			System.out.println("-------- List<? extends Number> ----");
			
			System.out.println("-------- List<? super Number> ----");
			
			Field listSuper = TypeDemo.class.getField("listSuper");
			printWildcardType(listSuper);
			
			System.out.println("-------- List<? super Number> ----");
			
			System.out.println("-------- Map<? extends String, ? super String> ----");
			
			Field map = TypeDemo.class.getField("map");
			printWildcardType(map);
			
			System.out.println("-------- Map<? extends String, ? super String> ----");
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		
		
		System.out.println("End --> WildcardType");
		
	}
	
	private static void printWildcardType(Field field) {
		Type genericType = field.getGenericType();
		if (genericType instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType)genericType;
			Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
			for (Type type : actualTypeArguments) {
				System.out.println("-----------------------");
				if (type instanceof WildcardType) {
					WildcardType wildcardType = (WildcardType) type;
					// getLowerBounds()：返回表示此类型变量下限的Type对象数组,但只得到super关键字后面的类型，
					// 如果没写super关键字，则返回空数组。
					System.out.println("wildcardType.getLowerBounds()" + Arrays.toString(wildcardType.getLowerBounds()));
					// getUpperBounds()：返回表示此类型变量上限的Type对象数组.类型的上边界的Type数组，
					// 实际上就是类型的直接父类，也就是extends后面的类型。
					// 而,在Java中,一个类只能有一个父类。如果没有使用`extends`声明父类，
					// 那么它的直接父类就是`Object`。
					System.out.println("wildcardType.getUpperBounds()" + Arrays.toString(wildcardType.getUpperBounds()));
				}
				System.out.println("-----------------------");
			}
		}
		
	}
}
